package textExcel;

public class RealCell extends Cell
{
	private final String[] parts;
	private final Spreadsheet spreadsheet;
	
	public RealCell(double value, Spreadsheet spreadsheet)
	{
		this("( " + value + " )", spreadsheet);
	}
	
    /**
     * precondition: isValidFormula(formula)
     * @param formula
     */
    public RealCell(String formula, Spreadsheet spreadsheet)
    {
    	this.parts = split(formula, spreadsheet);
    	
    	if(this.parts == null) // split returns null for invalid formulas
    		throw new IllegalArgumentException("Invalid formula");
    	
        this.spreadsheet = spreadsheet;
    }
    
    public boolean hasNumericValue()
	{
		return true;
	}
    
    public double numericValue()
    {
    	double value = this.value(this.parts[1]);
    	
    	for(int i = 2; i < this.parts.length - 2; i += 2)
    	{
    		Double nextValue = this.value(this.parts[i + 1]);
    		
    		if(nextValue == null)
    			throw new IllegalStateException("Referenced cell does not contain a numeric value");
    		
    		switch(this.parts[i])
    		{
    		case "+":
    			value += nextValue;
    			break;
    			
    		case "-":
    			value -= nextValue;
    			break;
    			
    		case "*":
    			value *= nextValue;
    			break;
    			
    		case "/":
    			value /= nextValue;
    			break;
    		}
    	}
    	
    	return value;
    }
    
    // returns null for cells with contents other than numeric
    private Double value(String cellReferenceOrNumber)
    {
    	try
    	{
    		return Double.parseDouble(cellReferenceOrNumber);
    	}
    	catch(NumberFormatException e)
    	{
    		if(this.spreadsheet.isValidCell(cellReferenceOrNumber) &&
    				this.spreadsheet.getCell(cellReferenceOrNumber).hasNumericValue())
    			return this.spreadsheet.getCell(cellReferenceOrNumber).numericValue();
    		else
    			return null;
    	}
    }
    
    public String toString()
    {
        String asString = "";
        
        for(String part : this.parts)
        	asString += part + " ";
        
        return asString;
    }

    public static boolean isValidFormula(String formula, Spreadsheet spreadsheet)
    {
    	return split(formula, spreadsheet) != null;
    }
    
    // returns null if formula is invalid
    private static String[] split(String formula, Spreadsheet spreadsheet)
    {
        String[] parts = formula.split(" ");
        
        // must have parentheses and be able to end with an operand
        if(parts.length < 3 || parts.length % 2 == 0 ||
        		! "(".equals(parts[0]) || ! ")".equals(parts[parts.length - 1]))
        	return null;
        
        for(int i = 1; i < parts.length - 1; i++)
        {
        	if(i % 2 != 0) // expecting operand
        	{
        		try
        		{
        			Double.parseDouble(parts[i]);
        		}
        		catch(NumberFormatException e)
        		{
        			if(!spreadsheet.isValidCell(parts[i]) || !spreadsheet.getCell(parts[i]).hasNumericValue())
        				return null;
        		}
        	}
        	else // expecting operator
        	{
        		switch(parts[i])
        		{
        		case "+":
        		case "-":
        		case "*":
        		case "/":
        			break;
        		
        		default:
        			return null;
        		}
        	}
        }
        
        return parts;
    }
}
